﻿using System;
using System.Collections.Generic;
using System.Windows.Forms;
using ArcEngine;
using ArcEngine.Graphics;
using ArcEngine.Input;
using System.Drawing;
using ArcEngine.Resources;


namespace DungeonEye
{
	class DungeonEye
	{
		/// <summary>
		/// Point d'entrée principal de l'application.
		/// </summary>
		[STAThread]
		static void Main()
		{
			Init();
			Video.Run();
		}


		/// <summary>
		/// Allows the game to perform any initialization it needs to before starting to run.
		/// This is where it can query for any required services and load any non-graphic
		/// related content.  Calling base.Initialize will enumerate through any components
		/// and initialize them as well.
		/// </summary>
		static void Init()
		{

			Messages = new List<ScreenMessage>();


			Video.Init();

			// Events 
			Keyboard.OnKeyDown += new EventHandler<PreviewKeyDownEventArgs>(OnKeyDown);
			Video.OnFrameTick += new EventHandler<FrameTickArgs>(OnFrameTick);
			Mouse.OnButtonDown += new EventHandler<MouseEventArgs>(OnMouseClick);


			// Enble the console
			Terminal.Enable = true;

			// Load data
			ResourceManager.LoadBank("data/data.bnk");


			// Init display
			Video.OpenRender(new Size(640, 400), false);
			Video.WindowCaption = "Dungeon Eye";
			Video.Blending = true;
			Video.ClearColor = Color.Black;
			Video.Font = ResourceManager.GetTTFFont("Browa");
			Video.Font.Color = Color.White;



			// Load tiles
			InterfaceTiles = ResourceManager.GetTileSet("Interface");
			InterfaceTiles.Zoom = new SizeF(2.0f, 2.0f);



			Dungeon = new Dungeon();
			Dungeon.Load("data/dungeon.xml");
			Dungeon.Init();



			// Team
			//Team = new Team();
			Team.Init();
			Team.Maze = Dungeon.StartMaze;
			Team.Location = Dungeon.StartCoord;




			Path path = new Path("");
			path.AddPoint(new Point(10, 10));
			path.AddPoint(new Point(20, 10));
			path.AddPoint(new Point(30, 10));

			path.IsOnPath(new Point(15, 11));

		}




		/// <summary>
		/// Allows the game to run logic such as updating the world,
		/// checking for collisions, gathering input, and playing audio.
		/// </summary>
		static void Update()
		{
			// Update the team status
			Team.Update();

			// Update the dungeon
			Dungeon.Update();

			// Remove older screen messages
			Messages.RemoveAll(delegate(ScreenMessage msg) { return DateTime.Now.AddSeconds(-5) > msg.Date ;});
		}



		/// <summary>
		/// This is called when the game should draw itself.
		/// </summary>
		static void Render()
		{
			// Clears the background
			Video.ClearBuffers();
			Video.Color = Color.White;

			// Bind the tiles
			InterfaceTiles.Bind();

			// The backdrop
			InterfaceTiles.Draw(0, Point.Empty);

			// Display the compass
			InterfaceTiles.Draw(5 + (int)Team.Direction * 3, new Point(224, 254));
			InterfaceTiles.Draw(6 + (int)Team.Direction * 3, new Point(154, 308));
			InterfaceTiles.Draw(7 + (int)Team.Direction * 3, new Point(298, 308));


			if (ShowInventory)
			{
				InterfaceTiles.Draw(18, new Point(354, 0));
				Team.CurrentHero.DrawHead(new Point(360, 2));

			}
			else
			{
				// Draw the team
				Team.Draw();
			}



			// Draw the dungeon
			Dungeon.Draw(Team.Maze, Team.Location, Team.Direction);




			// Display the last 3 messages
			int i = 0;
			foreach(ScreenMessage msg in Messages)
			{
				Video.Font.Color = msg.Color;
				Video.DrawText(new Point(10, 350 + i * 12), msg.Message);
				i++;
			}

			Video.DrawText(new Point(0, 320), Team.Location.ToString());

			// Swap buffers
			Video.SwapBuffers();
		}


		/// <summary>
		/// Display a message in the message zone
		/// </summary>
		/// <param name="msg">Message to display</param>
		/// <param name="color">Color of the message</param>
		static public void AddDisplayMessage(string msg, Color color)
		{
			Messages.Add(new ScreenMessage(msg, color));

			while (Messages.Count > 3)
				Messages.RemoveAt(0);
		}



		#region Events

		/// <summary>
		/// Fires every frame. 
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		static void OnFrameTick(object sender, FrameTickArgs e)
		{
			Update();
			Render();
		}




		/// <summary>
		/// On mouse click
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="e"></param>
		static void OnMouseClick(object sender, MouseEventArgs e)
		{
			// Turn left
			if (new Rectangle(10, 256, 38, 34).Contains(e.Location))
				Team.Rotate(TeamRotation.CounterClockwise);

			// Forward
			if (new Rectangle(48, 256, 40, 34).Contains(e.Location))
				Team.Move(0, -1);

			// Turn right
			if (new Rectangle(88, 256, 40, 34).Contains(e.Location))
				Team.Rotate(TeamRotation.Clockwise);

			// Move left
			if (new Rectangle(10, 290, 38, 34).Contains(e.Location))
				Team.Move(-1, 0);

			// Backward
			if (new Rectangle(48, 290, 40, 34).Contains(e.Location))
				Team.Move(0, 1);

			// Move right
			if (new Rectangle(88, 290, 40, 34).Contains(e.Location))
				Team.Move(1, 0);


			if (!ShowInventory)
			{

				for (int y = 0; y < Team.HeroCount / 2; y++)
				{
					for (int x = 0; x < 2; x++)
					{
						Video.Rectangle(new Rectangle(370 + x * 72, 4 + y * 52, 124, 18), true);

						// Name
						if (new Rectangle(370 + x * 144, 4 + y * 104, 124, 18).Contains(e.Location))
						{
							if (e.Button == MouseButtons.Left)
							{
								Team.SelectHero = y * 2 + x;
							}
							else if (e.Button == MouseButtons.Right)
							{
								AddDisplayMessage(Team.Heroes[y * 2 + x].Name + " : swap position", Color.White);
							}
						}

						// Inventory
						if (new Rectangle(370 + x * 144, 22 + y * 104, 62, 64).Contains(e.Location))
						{
							Team.SelectHero = y * 2 + x;
							ShowInventory = true;
						}

						// Left hand
						if (new Rectangle(434 + x * 144, 22 + y * 104, 60, 32).Contains(e.Location))
							AddDisplayMessage(Team.Heroes[y * 2 + x].Name + " : left hand", Color.White);

						// Right hand
						if (new Rectangle(434 + x * 144, 54 + y * 104, 60, 32).Contains(e.Location))
							AddDisplayMessage(Team.Heroes[y * 2 + x].Name + " : right hand", Color.White);

					}
				}
				
			}
			else
			{
				// Inventory
				if (new Rectangle(360, 4, 64, 64).Contains(e.Location))
					ShowInventory = false;

			}
		}




		/// <summary>
		/// On key down
		/// </summary>
		/// <param name="sender"></param>
		/// <param name="evt"></param>
		static void OnKeyDown(object sender, PreviewKeyDownEventArgs evt)
		{
			switch (evt.KeyCode)
			{
				// Byebye
				case Keys.Escape:
				{
					Video.Quit();
				}
				break;

				case Keys.I:
				{
					ShowInventory = !ShowInventory;
				}
				break;

				case Keys.F1:
				{
					Team.Maze = Dungeon.GetMaze("level_1");
					AddDisplayMessage("Loading level 1", Color.Red);
				}
				break;


				case Keys.F2:
				{
					Team.Maze = Dungeon.GetMaze("level_2");
					AddDisplayMessage("Loading level 3", Color.Green);
				}
				break;

				case Keys.F3:
				{
					Team.Maze = Dungeon.GetMaze("level_3");
					AddDisplayMessage("Loading level 3", Color.Blue);
				}
				break;


				// Turn left
				case Keys.A:
				{
					Team.Rotate(TeamRotation.CounterClockwise);
				}
				break;


				// Turn right
				case Keys.E:
				{
					Team.Rotate(TeamRotation.Clockwise);
				}
				break;


				// Move forward
				case Keys.Z:
				{
					Team.Move(0, -1);
				}
				break;

				// Move backward
				case Keys.S:
				{
					Team.Move(0, 1);
				}
				break;

				// Strafe left
				case Keys.Q:
				{
					Team.Move(-1, 0);
				}
				break;

				// Strafe right
				case Keys.D:
				{
					Team.Move(1, 0);
				}
				break;


				case Keys.F11:
				{
					Video.WaitVbl = !Video.WaitVbl;
				}
				break;



			}
		}



		#endregion



		#region Properties

		/// <summary>
		/// Tiles for the interface
		/// </summary>
		static TileSet InterfaceTiles;


		/// <summary>
		/// Dungeon to use
		/// </summary>
		static Dungeon Dungeon;


		/// <summary>
		/// The team
		/// </summary>
		//static Team Team;


		/// <summary>
		/// If true, display the inventory
		/// </summary>
		static bool ShowInventory;


		/// <summary>
		/// If ture, show the hero stats
		/// </summary>
		static bool ShowHeroStats;


		/// <summary>
		/// Last 3 messages to display
		/// </summary>
		static List<ScreenMessage> Messages;

		#endregion
	}

}
